using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Smallpointer.Resource;

namespace Smallpointer.Data.Common
{
    internal class DataMapUtil : DBase
    {
        public DataConfigMap EntityDataMap { get; private set; }
        public DataMap ValidInputDataMap { get; private set; }
        public DataMap ValidConditionMap { get; set; }
        public DataRelationMap EntityDataRelactional { get; private set; }
        public DataMapUtil(Data parent)
            : base(parent)
        {
            ValidInputMap();
        }
        public void ValidInputMap()
        {
            //get base map
            var content = GetConfigContentByName(Parent.Input.Name);
            EntityDataMap = GetPropertiesByContent(content);
            EntityDataMap.Name = Parent.Input.Name;
            //relational 
            EntityDataRelactional = GetRelationalByContent(content);

            //validate entity map
            GetValidateInputMap();
            //validate entity condition
            GetValidateConditionMap();
        }
        public string GetConfigContentByName(string name)
        {
            string xmlContent;
            switch (Parent.DBConfig.DBSapce)
            {
                case DataSpace.Resource:
                    xmlContent = ResourceReader.GetEmbeddedEntityMapConfig(Parent.Input.Name);
                    break;
                case DataSpace.File:
                    xmlContent = ResourceReader.GetDiskEntityMapConfig(Parent.Input.Name);
                    break;
                default:
                    throw new FileNotFoundException("entity configuration file can not be found. please re-install the project");
            }
            if (string.IsNullOrEmpty(xmlContent))
            {
                throw new Exception("Can not find the Configuration files of current entity.");
            }
            return xmlContent;
        }
        public DataConfigMap GetPropertiesByContent(string content)
        {
            var xml = new XmlDocument();
            var temp = new DataConfigMap();
            if (!string.IsNullOrEmpty(content))
            {
                xml.LoadXml(content);
                var root = xml.DocumentElement;
                if (root != null)
                {
                    var nameAttribute = root.Attributes["name"];
                    if (nameAttribute == null || string.IsNullOrEmpty(nameAttribute.Value))
                    {
                        throw new Exception("Invalidate entity configuration map,please add name attribute to root element.");
                    }
                    temp.Name = nameAttribute.Value;
                    var properties = root.SelectNodes("property/add");
                    if (properties != null)
                    {
                        foreach (XmlNode property in properties)
                        {
                            var keyAttribute = property.Attributes["key"];
                            if (keyAttribute == null || string.IsNullOrEmpty(keyAttribute.Value))
                            {
                                continue;
                            }
                            var key = keyAttribute.Value;
                            var item = new DataProperty();
                            var ps = item.GetType().GetProperties();
                            foreach (var propertyInfo in ps)
                            {
                                var attribute = property.Attributes[propertyInfo.Name.ToLower()];
                                if (attribute == null || string.IsNullOrEmpty(attribute.Value))
                                {
                                    continue;
                                }

                                if (propertyInfo.PropertyType == typeof(bool))
                                    propertyInfo.SetValue(item, attribute.Value == "true", null);
                                else
                                    propertyInfo.SetValue(item, attribute.Value, null);
                            }
                            temp.Add(key, item);
                        }
                    }
                }
            }
            return temp;
        }
        public DataRelationMap GetRelationalByContent(string content)
        {
            var temp = new DataRelationMap();
            var xml = new XmlDocument();
            if (!string.IsNullOrEmpty(content))
            {
                xml.LoadXml(content);
                var root = xml.DocumentElement;
                if (root != null)
                {
                    //parent
                    var nodes = root.SelectNodes("parent/add");
                    temp.Add("parent", new List<DataConfigMap>());
                    if (nodes != null)
                    {
                        var ps = typeof(DataRelational).GetProperties();
                        foreach (XmlNode node in nodes)
                        {
                            var attribute = node.Attributes["object"];
                            if (attribute == null || string.IsNullOrEmpty(attribute.Value))
                            {
                                continue;
                            }
                            var relation = new DataRelational();
                            foreach (var info in ps)
                            {
                                var valueAttribute = node.Attributes[info.Name.ToLower()];
                                if (valueAttribute == null || string.IsNullOrEmpty(valueAttribute.Value))
                                {
                                    continue;
                                }
                                info.SetValue(relation, valueAttribute.Value, null);
                            }

                            var subContent = GetConfigContentByName(relation.name);
                            if (!string.IsNullOrEmpty(subContent))
                            {
                                temp["parent"].Add(GetPropertiesByContent(subContent));
                            }
                        }
                    }

                    //child
                    nodes = root.SelectNodes("child/add");
                    temp.Add("child", new List<DataConfigMap>());
                    if (nodes != null)
                    {
                        var ps = typeof(DataRelational).GetProperties();
                        foreach (XmlNode node in nodes)
                        {
                            var attribute = node.Attributes["object"];
                            if (attribute == null || string.IsNullOrEmpty(attribute.Value))
                            {
                                continue;
                            }
                            var relation = new DataRelational();
                            foreach (var info in ps)
                            {
                                var valueAttribute = node.Attributes[info.Name.ToLower()];
                                if (valueAttribute == null || string.IsNullOrEmpty(valueAttribute.Value))
                                {
                                    continue;
                                }
                                info.SetValue(relation, valueAttribute.Value, null);
                            }

                            var subContent = GetConfigContentByName(relation.name);
                            if (!string.IsNullOrEmpty(subContent))
                            {
                                temp["child"].Add(GetPropertiesByContent(subContent));
                            }
                        }
                    }
                }
            }
            return temp;
        }
        public void GetValidateInputMap()
        {
            ValidInputDataMap = new DataMap { Name = EntityDataMap.Name };
            foreach (var keyValuePair in Parent.Input)
            {
                if (EntityDataMap.ContainsKey(keyValuePair.Key))
                {
                    ValidInputDataMap.Add(keyValuePair.Key, keyValuePair.Value);
                }
            }
        }
        public void GetValidateConditionMap()
        {
            ValidConditionMap = new DataMap { Name = EntityDataMap.Name };
            if (Parent.Condition == null)
            {
                ValidConditionMap = null;
                return;
            }
            foreach (var keyValuePair in Parent.Condition)
            {
                if (EntityDataMap.ContainsKey(keyValuePair.Key))
                {
                    ValidConditionMap.Add(keyValuePair.Key, keyValuePair.Value);
                }
            }
        }
        public override void Dispose()
        {
            EntityDataMap.Clear();
            ValidInputDataMap.Clear();
            EntityDataRelactional.Clear();
        }
    }
}